/* ******************************************************************
 * This file is part of the escal project and distributed under the
 * terms of the GNU General Public License Version 3
 * Copyright (C) 2008 Epocher (xijiaosdq@gmail.com)
 * See COPYING file for licensing information.
 *******************************************************************/

#include "escal_gui.h"
#include "escal.h"
#include "config.h"
#include "escal_settings.h"
#include "initializer.h"
#include "preference_dialog.h"
#include "task_info_widget.h"
#include "utils/scanner_dialog.h"
#include <QClipboard>
#include <QSystemTrayIcon>

using namespace Escal;

EscalGui::EscalGui(QWidget* parent): QMainWindow(parent)
{
	setupUi(this);
	/*
	 * we may not need e_UrlDialog, so we set it to NULL
	 * until the first time we use it
	 */
	urlDialog=NULL;
	preferenceDialog=NULL;
	scannerDialog=NULL;
	trayIcon=new QSystemTrayIcon(windowIcon(), this);
	connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
		this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
	trayIcon->setVisible(true);

	clipboard = QApplication::clipboard();
	
	buildModels();
	buildViews();
	buildContextMenus();

	if(settings->value("MainWindowSize")!=QVariant()){
		resize(settings->value("MainWindowSize").toSize());
	}

	QVariantList sizesV;
	QList<int> sizes;
	sizesV=settings->value("ViewSplitterSizes1").toList();
	if(sizesV!=QVariantList()){
		QVariant i;
		foreach(i, sizesV){
			qDebug () << i.toInt();
			sizes << i.toInt();
		}
		splitter1->setSizes(sizes);
	}
	sizes.clear();
	sizesV=settings->value("ViewSplitterSizes2").toList();
	if(sizesV!=QVariantList()){
		QVariant i;
		foreach(i, sizesV){
			sizes << i.toInt();
		}
		splitter2->setSizes(sizes);
	}
	sizesV=settings->value("UndoneHeaderSizes").toList();
	if(sizesV!=QVariantList()&&
			sizesV.size()==undoneTaskModel->columnCount()){
		int i;
		for(i=0;i<sizesV.size();i++){
			undoneTaskView->header()->resizeSection(i,
					sizesV[i].toInt());
		}
	}
	sizesV=settings->value("DoneHeaderSizes").toList();
	if(sizesV!=QVariantList()&&
			sizesV.size()==doneTaskModel->columnCount()){
		int i;
		for(i=0;i<sizesV.size();i++){
			doneTaskView->header()->resizeSection(i,
					sizesV[i].toInt());
		}
	}


	connect(undoneTaskView, SIGNAL(pressed(const QModelIndex &)),
		this, SLOT(undoneTaskClicked(const QModelIndex &)));
	connect(doneTaskView, SIGNAL(pressed(const QModelIndex &)),
		this, SLOT(doneTaskClicked(const QModelIndex &)));
	connect(folderView, SIGNAL(pressed(const QModelIndex &)),
		this, SLOT(folderClicked(const QModelIndex &)));
	connect(clipboard, SIGNAL(dataChanged()),
	       this, SLOT(clipboardDataChanged()) );
	connect(actionAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
	connect(actionAddFolder, SIGNAL(triggered()),
		folderListModel, SLOT(newFolder()));
	connect(actionRemoveFolder, SIGNAL(triggered()),
		this, SLOT(deleteSelectedFolder()));
	connect(actionShiftUp,SIGNAL(triggered()),
		this, SLOT(moveUpSelectedFolder()));
	connect(actionShiftDown, SIGNAL(triggered()),
		this, SLOT(moveDownSelectedFolder()));
	connect(actionToTop, SIGNAL(triggered()),
		this, SLOT(moveToTopSelectedFolder()));
	connect(actionToBottom, SIGNAL(triggered()),
		this, SLOT(moveToBottomSelectedFolder()));
	connect(eInit, SIGNAL(passUrl(QString)),
		this, SLOT(getPassedUrl(QString)));
	//connect(qApp, SIGNAL(lastWindowClosed()), this, SLOT(quit()));
	undoneTaskClicked();
}

EscalGui::~EscalGui(){
	if(urlDialog!=NULL) delete urlDialog;
	if(preferenceDialog!=NULL) delete preferenceDialog;
	saveData();
};

void EscalGui::buildModels(){
	undoneTaskModel=new UndoneTaskModel(this);
	undoneTaskModel->loadTaskList();
	connect(undoneTaskModel, SIGNAL(taskCompleted(BaseTask *)),
		this, SLOT(taskCompleted(BaseTask *)));
	connect(undoneTaskModel, SIGNAL(taskDeleted(BaseTask *)),
		this, SLOT(taskDeleted(BaseTask *)));

	doneTaskModel=new DoneTaskModel(this);
	doneTaskModel->loadTaskList();
	connect(doneTaskModel, SIGNAL(taskDeleted(BaseTask *)),
		this, SLOT(taskDeleted(BaseTask *)));

	folderListModel=new FolderListModel(this);
	connect(settings, SIGNAL(foldersChanged()),
		folderListModel, SLOT(foldersChanged()));

	dirModel = new QDirModel(this);
};

void EscalGui::buildViews(){
	splitter1 = new QSplitter(centralwidget);
	splitter1->setObjectName(QString::fromUtf8("splitter1"));
	splitter1->setMaximumSize(QSize(16777215, 16777215));
	splitter1->setOrientation(Qt::Vertical);

	undoneTaskView = new UndoneTaskView(splitter1);
	undoneTaskView->setObjectName(QString::fromUtf8("undoneTaskView"));
	undoneTaskView->setModel(undoneTaskModel);
	undoneTaskView->setSelectionMode(QAbstractItemView::ExtendedSelection);
	undoneTaskView->setSelectionBehavior(QAbstractItemView::SelectRows);
	undoneTaskView->setRootIsDecorated(false);
	undoneTaskView->setSortingEnabled(true);
	undoneTaskViewDelegate = new UndoneTaskViewDelegate(this);
	undoneTaskView->setItemDelegate(undoneTaskViewDelegate);

	doneTaskView = new DoneTaskView(splitter1);
	doneTaskView->setObjectName(QString::fromUtf8("doneTaskView"));
	doneTaskView->setModel(doneTaskModel);
	doneTaskView->setSelectionMode(QAbstractItemView::ExtendedSelection);
	doneTaskView->setSelectionBehavior(QAbstractItemView::SelectRows);
	doneTaskView->setRootIsDecorated(false);
	doneTaskView->setSortingEnabled(true);

	splitter2 = new QSplitter(splitter1);
	splitter2->setObjectName(QString::fromUtf8("splitter2"));
	splitter2->setOrientation(Qt::Horizontal);

	folderView = new QTreeView(splitter2);
	folderView->setModel(folderListModel);
	
	infoWindow = new QWidget(splitter2);
	QLayout *layout = new QGridLayout(infoWindow);
	infoWindow->setLayout(layout);

	dirView = new QTreeView(infoWindow);
	taskInfoWidget = new TaskInfoWidget(infoWindow);
	connect(undoneTaskModel, SIGNAL(taskDeleted(BaseTask*)),
		taskInfoWidget, SLOT(taskDeleted(BaseTask *)));
	connect(doneTaskModel, SIGNAL(taskDeleted(BaseTask*)),
		taskInfoWidget, SLOT(taskDeleted(BaseTask *)));
	layout->addWidget(dirView);
	layout->addWidget(taskInfoWidget);
	dirView->hide();
	taskInfoWidget->hide();

	splitter1->addWidget(undoneTaskView);
	splitter1->addWidget(doneTaskView);
	splitter2->addWidget(folderView);
	splitter2->addWidget(infoWindow);
	splitter1->addWidget(splitter2);
	verticalLayout->addWidget(splitter1);

};

void EscalGui::buildContextMenus(){
	undoneTaskMenu = new QMenu(this);
	undoneTaskMenu->addAction(actionNew);
	undoneTaskMenu->addAction(actionStart);
	undoneTaskMenu->addAction(actionPause);
	undoneTaskMenu->addAction(actionStop);
	undoneTaskMenu->addSeparator();
	undoneTaskMenu->addAction(actionIncrease);
	undoneTaskMenu->addAction(actionCut_Down);
	undoneTaskMenu->addSeparator();
	undoneTaskMenu->addAction(actionOpen);
	undoneTaskMenu->addAction(actionCancel);
	undoneTaskMenu->addAction(actionDeleteData);

	doneTaskMenu = new QMenu(this);
	doneTaskMenu->addAction(actionOpen);
	doneTaskMenu->addAction(actionDeleteData);
	doneTaskMenu->addAction(actionCancel);

	infoMenu = new QMenu(this);

	resOrMin = new QAction(tr("Minimize"), this);
	resOrMin->setStatusTip(tr("Minimize or restore the main window."));
	connect(resOrMin, SIGNAL(triggered()), this, SLOT(restoreOrMinimize()));
	
	trayMenu = new QMenu(this);
	trayMenu->addAction(actionNew);
	trayMenu->addSeparator();
	trayMenu->addAction(actionPreference);
	trayMenu->addAction(resOrMin);
	trayMenu->addSeparator();
	trayMenu->addAction(actionExit);
	trayIcon->setContextMenu(trayMenu);
}

void EscalGui::closeEvent ( QCloseEvent * event ){
	qDebug() << " EscalGui::closeEvent ( QCloseEvent * event )";
	event->ignore();
	restoreOrMinimize();
}

bool EscalGui::close(){
	qDebug() << "EscalGui::close()";
	qApp->quit();
	return QMainWindow::close();
};

void EscalGui::saveData(){
	qDebug() << "EscalGui::saveData()";
	QVariantList sizes;
	int i;
	for(i=0;i<undoneTaskModel->columnCount();i++){
		sizes<<undoneTaskView->header()->sectionSize(i);
	}
	settings->setValue("UndoneHeaderSizes", sizes);
	sizes.clear();
	for(i=0;i<doneTaskModel->columnCount();i++){
		sizes<<doneTaskView->header()->sectionSize(i);
	}
	settings->setValue("DoneHeaderSizes", sizes);
	sizes.clear();
	foreach(i, splitter1->sizes()){
		sizes<<i;
	}
	settings->setValue("ViewSplitterSizes1", sizes);
	sizes.clear();
	foreach(i, splitter2->sizes()){
		sizes<<i;
	}
	settings->setValue("ViewSplitterSizes2", sizes);
	settings->setValue("MainWindowSize", size());
	undoneTaskModel->saveTaskList();
	doneTaskModel->saveTaskList();
	undoneTaskModel->stopTask();
}

void EscalGui::about(){
	QMessageBox::about(this, "about eGear",
		tr("<b>eGear</b> is a download tool based on QT4<br>"
		"Homepage: <a href=\"http://egear.googlecode.com\" >"
		"egear.googlecode.com </a> <br>"
		"current version: <b>%1</b><br>"
		"Copyright (C) 2008 Epocher(<a href=\""
		"mailto:xijiaosdq@gmail.com\">xijiaosdq@gmail.com</a>). "
		"All Right reserved.")
		.arg(VERSION) );
};

void EscalGui::aboutQt(){
};

void EscalGui::newTask(const QString &urlStr){
	show();
	if(urlDialog==NULL) urlDialog=new UrlDialog();
	urlDialog->reset();
	if(urlStr!=QString()){
		urlDialog->setUrlStr(urlStr);
	}
	for(;;){
		if(urlDialog->exec() != QDialog::Accepted) 
			return;
		QUrl url = urlDialog->getUrl();
		QString fileName = urlDialog->getFileName();
		QString folderName = urlDialog->getFolderName();
		if(url==QUrl() || fileName == QString() 
				|| folderName == QString()){
			QMessageBox::warning(this, tr("warning"),
				tr("empty arguments!"));
			continue;
		}
		int threadNum = urlDialog->getThreadNum();
		QDir dir(folderName);
		if(!dir.exists() && !dir.mkdir(folderName)){
			QMessageBox::warning(this, tr("warning"),
				tr("create directory failed!"));
			continue;
		}
		if(!dir.mkdir(".egear_test_access") ||
					!dir.rmpath(".egear_test_access")){
			QMessageBox::critical(this, tr("warning"),
				tr("directory not writable!"));
			continue;
		}
		QString postfix, postfix2;
		int p=fileName.lastIndexOf(".");
		if(p){
			postfix = fileName;
			postfix.remove(0, p);
			fileName.resize(p);
			p=fileName.lastIndexOf(".");
			if(p){
				postfix2 = fileName;
				postfix2.remove(0, p);
				if(postfix2==".tar"){
					fileName.resize(p);
					postfix = postfix2 + postfix;
				}
			}
		}
		if(dir.exists(QString("%1%2").arg(fileName).arg(postfix))){
			for(int i=1;;i++){
				if(!dir.exists(QString("%1(%3)%2")
					.arg(fileName).arg(postfix).arg(i)))
				{
					fileName = QString("%1(%3)%2")
					.arg(fileName).arg(postfix).arg(i);
					break;
				}
			}
		}else{
			fileName = QString("%1%2").arg(fileName).arg(postfix);
		}
		QFile file(dir.filePath(fileName));
		file.open(QIODevice::WriteOnly);
		file.close();
		addTask(url, folderName, 
			fileName , threadNum);
		break;
	}
	undoneTaskModel->saveTaskList();
};

void EscalGui::addTask(QUrl url, QString folderName, QString fileName,
			int threadNum){

	TaskFactory factory;
	BaseTask *task=factory.createNewTask(url, folderName, 
		fileName , threadNum, this);
	if(task==NULL){
		QMessageBox::critical(this, tr("error"),
		tr("fail to create a task"));
		return;
	}
	undoneTaskModel->addTask(task);
	if(settings->value("eGear/StartTaskAfterAdded").toBool()){
		task->start();
	}
};

void EscalGui::startSelected(){
	QItemSelectionModel *selectionModel = undoneTaskView->selectionModel();
	QModelIndexList indexes = selectionModel->selectedRows();
	QModelIndex index;

	foreach(index, indexes) {
		undoneTaskModel->startTask(index);
	}
};

void EscalGui::pauseSelected(){
	QItemSelectionModel *selectionModel = undoneTaskView->selectionModel();
	QModelIndexList indexes = selectionModel->selectedRows();
	QModelIndex index;

	foreach(index, indexes) {
		undoneTaskModel->pauseTask(index);
	}

};
void EscalGui::stopSelected(){
	QItemSelectionModel *selectionModel = undoneTaskView->selectionModel();
	QModelIndexList indexes = selectionModel->selectedRows();
	QModelIndex index;

	foreach(index, indexes) {
		undoneTaskModel->stopTask(index);
	}

};

void EscalGui::increaseSelected(){
	QItemSelectionModel *selectionModel = undoneTaskView->selectionModel();
	QModelIndexList indexes = selectionModel->selectedRows();
	QModelIndex index;

	foreach(index, indexes) {
		undoneTaskModel->increaseTask(index);
	}
	undoneTaskModel->saveTaskList();
};
void EscalGui::cutDownSelected(){
	QItemSelectionModel *selectionModel = undoneTaskView->selectionModel();
	QModelIndexList indexes = selectionModel->selectedRows();
	QModelIndex index;

	foreach(index, indexes) {
		undoneTaskModel->cutDownTask(index);
	}
	undoneTaskModel->saveTaskList();
};

void EscalGui::cancelSelected(){
	qDebug() << "EscalGui::cancelSelected()";
	QItemSelectionModel *selectionModel = undoneTaskView->selectionModel();
	QModelIndexList indexes = selectionModel->selectedRows();
	undoneTaskModel->deleteTasks(indexes);

	selectionModel = doneTaskView->selectionModel();
	indexes = selectionModel->selectedRows();
	doneTaskModel->deleteTasks(indexes);
	undoneTaskModel->saveTaskList();
	doneTaskModel->saveTaskList();
};

void EscalGui::deleteDataSelected(){
	QItemSelectionModel *selectionModel = undoneTaskView->selectionModel();
	QModelIndexList indexes = selectionModel->selectedRows();
	undoneTaskModel->deleteDataTasks(indexes);
	
	selectionModel = doneTaskView->selectionModel();
	indexes = selectionModel->selectedRows();
	doneTaskModel->deleteDataTasks(indexes);
	
	undoneTaskModel->saveTaskList();
	doneTaskModel->saveTaskList();
};

void EscalGui::deleteSelectedFolder(){
	QItemSelectionModel *selectionModel = folderView->selectionModel();
	QModelIndexList indexList = selectionModel->selectedRows();
	if(indexList.size()!=0){
		QModelIndex index = indexList[0];
		folderListModel->deleteFolder(index);
	}
};

void EscalGui::moveUpSelectedFolder(){
	QItemSelectionModel *selectionModel = folderView->selectionModel();
	QModelIndexList indexList = selectionModel->selectedRows();
	if(indexList.size()!=0){
		QModelIndex index = indexList[0];
		folderListModel->moveUpFolder(index);
	}
};

void EscalGui::moveDownSelectedFolder(){
	QItemSelectionModel *selectionModel = folderView->selectionModel();
	QModelIndexList indexList = selectionModel->selectedRows();
	if(indexList.size()!=0){
		QModelIndex index = indexList[0];
		folderListModel->moveDownFolder(index);
	}
};

void EscalGui::moveToTopSelectedFolder(){
	QItemSelectionModel *selectionModel = folderView->selectionModel();
	QModelIndexList indexList = selectionModel->selectedRows();
	if(indexList.size()!=0){
		QModelIndex index = indexList[0];
		folderListModel->moveToTopFolder(index);
	}
};

void EscalGui::moveToBottomSelectedFolder(){
	QItemSelectionModel *selectionModel = folderView->selectionModel();
	QModelIndexList indexList = selectionModel->selectedRows();
	if(indexList.size()!=0){
		QModelIndex index = indexList[0];
		folderListModel->moveToBottomFolder(index);
	}
};

void EscalGui::preference(){
	if(!preferenceDialog)
		preferenceDialog = new PreferenceDialog;
	preferenceDialog->show();
};

void EscalGui::restoreOrMinimize(){
	qDebug() << "EscalGui::restoreOrMinimize()";
	if(isHidden()){
		show();
		resOrMin->setText(tr("Minimize"));
	}
	else{
		hide();
		resOrMin->setText(tr("Restore"));
	}

}

void EscalGui::taskCompleted(BaseTask *task){
	doneTaskModel->addTask(task);
	doneTaskModel->saveTaskList();
};

void EscalGui::taskDeleted(BaseTask *task){
	delete task;
};

void EscalGui::clipboardDataChanged(){
	qDebug() << "EscalGui::clipboardDataChanged";
	QString clipText = clipboard->text();
	if( !clipText.startsWith("http://",Qt::CaseInsensitive)
		&& !clipText.startsWith("ftp://",Qt::CaseInsensitive)){
		qDebug() << "no my business";
		return;
	}
	QStringList postfixs = settings->value("eGear/WatchedLinksuffixList")
		.toStringList();
	QString postfix;
	foreach(postfix, postfixs){
		if(clipText.endsWith(postfix)){
			newTask();
			return;
		}
	}
}

void EscalGui::undoneTaskClicked(const QModelIndex & index){
	qDebug() << "EscalGui::undoneTaskClicked";
	doneTaskView->clearSelection();
	if(index==QModelIndex()){
		actionStart->setEnabled(false);
		actionPause->setEnabled(false);
		actionStop->setEnabled(false);
		actionIncrease->setEnabled(false);
		actionCut_Down->setEnabled(false);
		actionOpen->setEnabled(false);
		actionCancel->setEnabled(false);
		actionDeleteData->setEnabled(false);
		return ;
	}
	else{
		actionStart->setEnabled(true);
		actionPause->setEnabled(true);
		actionStop->setEnabled(true);
		actionIncrease->setEnabled(true);
		actionCut_Down->setEnabled(true);
		actionOpen->setEnabled(true);
		actionCancel->setEnabled(true);
		actionDeleteData->setEnabled(true);
	}
	BaseTask *task = undoneTaskModel->getTask(index);
	taskInfoWidget->watch(task);
	dirView->hide();
	taskInfoWidget->show();

};

void EscalGui::doneTaskClicked(const QModelIndex & index){
	undoneTaskView->clearSelection();
	actionStart->setEnabled(false);
	actionPause->setEnabled(false);
	actionStop->setEnabled(false);
	actionIncrease->setEnabled(false);
	actionCut_Down->setEnabled(false);
	if(index==QModelIndex()){
		actionOpen->setEnabled(false);
		actionCancel->setEnabled(false);
		actionDeleteData->setEnabled(false);
		return;
	}
	else{
		actionOpen->setEnabled(true);
		actionCancel->setEnabled(true);
		actionDeleteData->setEnabled(true);
	}
	BaseTask *task = doneTaskModel->getTask(index);
	taskInfoWidget->watch(task);
	dirView->hide();
	taskInfoWidget->show();
};

void EscalGui::folderClicked(const QModelIndex & index){
	dirView->setModel(dirModel);
	QString folderPath = index.model()->data(index).toString();
	dirView->setRootIndex(dirModel->index(folderPath));
	taskInfoWidget->hide();
	dirView->show();
};

void EscalGui::htmlScanner(){
	qDebug() << "EscalGui::htmlScanner()";
	if(scannerDialog==NULL){
		scannerDialog=new ScannerDialog(this);
		connect(scannerDialog, 
			SIGNAL(newTask(	QUrl, QString, QString,int)),
			this, SLOT(addTask(QUrl, QString, QString,int)));
	}
	if(scannerDialog->isHidden()){
		scannerDialog->show();
	}

};

void EscalGui::contextMenuEvent ( QContextMenuEvent * event ){
	QPoint p=event->globalPos();
	QHeaderView *header;
	if(undoneTaskView->rect().contains(
			undoneTaskView->mapFromGlobal(p))){
		header = undoneTaskView->header();
		if(!header->rect().contains(
				header->mapFromGlobal(p))){
			undoneTaskMenu->exec(event->globalPos());
		}
	}
	else if(doneTaskView->rect().contains(
			doneTaskView->mapFromGlobal(p))){
		header = doneTaskView->header();
		if(!header->rect().contains(
				header->mapFromGlobal(p))){
			doneTaskMenu->exec(event->globalPos());
		}
	}
	else if(folderView->geometry().contains(
			folderView->mapFromGlobal(p))){
		header = folderView->header();
		if(!header->rect().contains(
				header->mapFromGlobal(p))){
			menuFolder->exec(event->globalPos());
		}
	}
	else if(dirView->geometry().contains(
			dirView->mapFromGlobal(p))){

		infoMenu->exec(event->globalPos());
	}

	
	/* QMenu menu(this);
	menu.addAction(actionNew);
	menu.addAction(actionStart);
	menu.addAction(actionPause);
	menu.addAction(actionStop);
	menu.addSeparator();
	menu.addAction(actionIncrease);
	menu.addAction(actionCut_Down);
	menu.addSeparator();
	menu.addAction(actionCancel);
	menu.exec(event->globalPos());
	*/
};

void EscalGui::getPassedUrl(const QString &urlStr){
	qDebug() << "getPassedUrl" << urlStr;
	newTask(urlStr);
}


void EscalGui::trayActivated(QSystemTrayIcon::ActivationReason reason ){
	if(reason==QSystemTrayIcon::DoubleClick){
		restoreOrMinimize();
	}
}

